package cn.fintecher.pangolin.service.dataimp.service;

import cn.fintecher.pangolin.common.annotation.ExcelAnno;
import cn.fintecher.pangolin.common.exception.BadRequestException;
import cn.fintecher.pangolin.common.model.CaseInfoPropertyResponse;
import cn.fintecher.pangolin.common.utils.BeanUtils;
import cn.fintecher.pangolin.common.utils.InnerServiceUrl;
import cn.fintecher.pangolin.common.utils.SaxParseExcelUtil;
import cn.fintecher.pangolin.common.utils.ZWDateUtil;
import cn.fintecher.pangolin.entity.elastic.ImportExcelConfigItem;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;
import org.springframework.web.client.RestTemplate;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;

@Service
@Slf4j
public class ApprovalImportDataService {

    @Autowired
    private RestTemplate restTemplate;

    InputStream readFile(String fileId) {
        //获取文件
        HttpHeaders headers = new HttpHeaders();
        ResponseEntity<byte[]> response = restTemplate.exchange(InnerServiceUrl.COMMON_SERVICE_GETFILEBYID.concat("/").concat(fileId),
                HttpMethod.GET, new HttpEntity<byte[]>(headers), byte[].class);
        List<String> content = response.getHeaders().get("Content-Disposition");
        if (Objects.isNull(content) || content.isEmpty()) {
            throw new BadRequestException(null, "importExcelData", "templateFile.is.illegal");
        }
        if (!content.get(0).endsWith(SaxParseExcelUtil.EXCEL_TYPE_XLSX)) {
            throw new BadRequestException(null, "importExcelData", "file.format.error");
        }
        byte[] result = response.getBody();
        InputStream inputStream = new ByteArrayInputStream(result);
        return inputStream;
    }

    /***
     * Excel解析导入的数据
     * @param inputStream
     * @return
     */
    List<Map<String, String>> parseApprovalImportData(InputStream inputStream) {
        Map<Integer, List<Map<String, String>>> dataMap = null;
        List<Map<String, String>> sheetDataList = null;
        try {
            log.info("解析数据文件开始........");
            StopWatch watch = new StopWatch();
            watch.start();
            //数据信息
            dataMap = SaxParseExcelUtil.parseExcel(inputStream, 1, 1, -1, 1);
            watch.stop();
            log.info("解析数据文件结束，耗时：{}", watch.getTotalTimeMillis());
            //获取第一个Sheet的数据
            sheetDataList = dataMap.get(1);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return sheetDataList;
    }

    /**
     * 将申请的Excel Model转化为MAP
     *
     * @param inputStream
     * @return
     */
     Map<String, ImportExcelConfigItem> excelConfigItemToMap(List<Map<String, String>> heardList, InputStream inputStream, List<Class<?>> objClassList) {
        List<CaseInfoPropertyResponse> responses = getObjejctProperty(objClassList);
        Map<String, ImportExcelConfigItem> itemMap = new HashMap<>();
        if (heardList.size() > 0) {
            Map<String, String> map = heardList.get(0);
            for (CaseInfoPropertyResponse response : responses) {
                ImportExcelConfigItem item = new ImportExcelConfigItem();
                for (Map.Entry<String, String> filed : map.entrySet()) {
                    if (response.getName().equals(filed.getValue())) {
                        BeanUtils.copyProperties(response, item);
                        item.setCol(filed.getKey());
                    }
                }
                itemMap.put(item.getCol(), item);
            }
        }
        return itemMap;
    }

    /**
     * 获取指定类的属性
     */
    public List<CaseInfoPropertyResponse> getObjejctProperty(List<Class<?>> objClassList) {
        List<CaseInfoPropertyResponse> caseInfoPropertyResponseList = new ArrayList<>();
        for (Class<?> objClass : objClassList) {
            Field[] fields = objClass.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(ExcelAnno.class)) {
                    ExcelAnno f = field.getAnnotation(ExcelAnno.class);
                    CaseInfoPropertyResponse caseInfoPropertyResponse = new CaseInfoPropertyResponse();
                    caseInfoPropertyResponse.setAttribute(field.getName());
                    caseInfoPropertyResponse.setName(f.cellName());
                    caseInfoPropertyResponse.setPropertyType(f.fieldType().name());
                    caseInfoPropertyResponseList.add(caseInfoPropertyResponse);
                }
            }
        }
        return caseInfoPropertyResponseList;
    }

    /**
     * 解析每行数据转为对应的实体对象
     */
    public void parseCellMap(Object obj, String cellValue, ImportExcelConfigItem importExcelConfigItem, List<String> errorList,
                             long rowIndex, int sheetIndex) {
        try {
            Field field = obj.getClass().getDeclaredField(importExcelConfigItem.getAttribute());
            //打开实体中私有变量的权限
            field.setAccessible(true);
            Object object = fomatValue(field, cellValue, errorList, rowIndex, importExcelConfigItem.getCol(), sheetIndex);
            field.set(obj, object);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 格式化数据
     *
     * @param field
     * @param cellValue
     * @return
     */
    private Object fomatValue(Field field, String cellValue, List<String> errorList, long rowIndex, String colStr, int sheetNum) {
        if (StringUtils.isEmpty(cellValue)) {
            return null;
        }
        Object obj = null;
        ExcelAnno.FieldDataType fieldDataType = field.getAnnotation(ExcelAnno.class).fieldDataType();
        switch (fieldDataType) {
            case STRING:
                obj = cellValue;
                break;
            case INTEGER:
                try {
                    obj = Integer.parseInt(cellValue);
                } catch (NumberFormatException e) {
                    log.error(e.getMessage(), e);
                    errorList.add(createErrorStr(cellValue, "数值", rowIndex, colStr, sheetNum));
                }
                break;
            case DOUBLE:
                try {
                    BigDecimal bigDecimal = new BigDecimal(cellValue.replaceAll(",", ""));
                    obj = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                } catch (NumberFormatException e) {
                    log.error(e.getMessage(), e);
                    errorList.add(createErrorStr(cellValue, "数值", rowIndex, colStr, sheetNum));
                }
                break;
            case DATE:
                try {
                    if (cellValue.matches("\\d{4}/\\d{1,2}/\\d{1,2}")) {
                        obj = ZWDateUtil.getUtilDate(cellValue, "yyyy/MM/dd");
                    } else if (cellValue.matches("\\d{4}-\\d{1,2}-\\d{1,2}")) {
                        obj = ZWDateUtil.getUtilDate(cellValue, "yyyy-MM-dd");
                    } else if (cellValue.matches("^\\d{4}\\d{1,2}\\d{1,2}")) {
                        obj = ZWDateUtil.getUtilDate(cellValue, "yyyyMMdd");
                    } else if (cellValue.matches("\\d{4}.\\d{1,2}.\\d{1,2}")) {
                        obj = ZWDateUtil.getUtilDate(cellValue, "yyyy.MM.dd");
                    } else if (cellValue.matches("\\d{1,2}/\\d{1,2}/\\d{4}")) {
                        obj = ZWDateUtil.getUtilDate(cellValue, "MM/dd/yyyy");
                    } else if (cellValue.matches("\\d{1,2}/\\d{1,2}/\\d{2}")) {
                        obj = ZWDateUtil.getUtilDate(cellValue, "MM/dd/yy");
                    } else if (cellValue.matches("\\d{1,2}/\\d{1,2}/\\d{4}")) {
                        obj = ZWDateUtil.getUtilDate(cellValue, "MM/dd/yyyy");
                    } else if (cellValue.matches("\\d{4}-\\d{1,2}-\\d{1,2}\\s+([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$")) {
                        obj = ZWDateUtil.getUtilDate(cellValue, "yyyy-MM-dd HH:mm:ss");
                    } else {
                        obj = null;
                    }
                    break;
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                    errorList.add(createErrorStr(cellValue, "日期", rowIndex, colStr, sheetNum));
                }
            default:
                obj = cellValue;
                break;
        }
        return obj;
    }

    /**
     * 拼装错误信息
     *
     * @param cellValue
     * @param remark
     * @param rowIndex
     * @param colStr
     * @return
     */
    private String createErrorStr(String cellValue, String remark, long rowIndex, String colStr, int sheetNum) {
        return "第[".concat(String.valueOf(sheetNum)).concat("]sheet页的第[").concat(String.valueOf(rowIndex)).
                concat("]行,第[").concat(colStr).concat("]列的值[").
                concat(cellValue).concat("] 不能转为[").concat(remark).concat("]类型的，请检查模板或Excel数值");
    }
}
